<?php

namespace App\Service;


use GuzzleHttp\Client;
use Illuminate\Support\Facades\Cache;
use Illuminate\Foundation\Testing\HttpException;


class JsSDK
{
    private $appId;
    private $appSecret;
    protected $httpClient;

    public function __construct()
    {
        $this->appId = config('services.wechat.client_id');
        $this->appSecret = config('services.wechat.client_secret');
        $this->httpClient = $this->getHttpClient();
    }

    public function getSignPackage()
    {
        $jsapiTicket = $this->getJsApiTicket();
        $https = array_get($_SERVER, 'https');
        $serverPort = array_get($_SERVER, 'SERVER_PORT');
        $protocol = (!empty($https) && $https = 'off' || $serverPort == 443) ? "https://" : "http://";

        $host = array_get($_SERVER, 'HTTP_HOST');
        $requestUri = array_get($_SERVER, 'REQUEST_URI');

        $url = "$protocol$host$requestUri";

        $timestamp = time();
        $nonceStr = $this->createNonceStr();

        $string = "jsapi_ticket=$jsapiTicket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";

        $signature = sha1($string);

        $signPackage = array(
            "appId" => $this->appId,
            "nonceStr" => $nonceStr,
            "timestamp" => $timestamp,
            "url" => $url,
            "signature" => $signature,
            "rawString" => $string
        );
        return $signPackage;
    }


    public function getTokenUrl()
    {
        return 'https://api.weixin.qq.com/cgi-bin/token';
    }


    private function getJsApiTicket()
    {

        $ticket = Cache::get('jsapi_ticket');

        if (!$ticket) {
            $accessToken = $this->getAccessToken();
            $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
            $response = $this->getHttpClient()->get($url, [
                'query' => [
                    'type' => 'jsapi',
                    'access_token' => $accessToken
                ]
            ]);

            $res = json_decode($response->getBody(), true);

            if (array_get($res, 'ticket')) {
                $ticket = array_get($res, 'ticket');
                $expire = array_get($res, 'expires_in');
                Cache::put('jsapi_ticket', $ticket, $expire / 60);
            } else {
                throw new HttpException('get jsapi ticket error' . json_encode($res));
            }
        }

        return $ticket;
    }

    private function getAccessToken()
    {
        if (Cache::has('access_token')) {
            return Cache::get('access_token');
        }

        $response = $this->getHttpClient()->get($this->getTokenUrl(), [
            'query' => [
                'grant_type' => 'client_credential',
                'appid' => $this->appId,
                'secret' => $this->appSecret,
            ]
        ]);

        $res = json_decode($response->getBody(), true);

        if (array_get($res, 'access_token')) {
            $access_token = array_get($res, 'access_token');
            $expire = array_get($res, 'expires_in');
            Cache::put('access_token', $access_token, $expire / 60);
            return $access_token;
        } else {
            throw new HttpException('get access token error' . json_encode($res));
        }
    }


    protected function getHttpClient()
    {
        if (is_null($this->httpClient)) {
            $this->httpClient = new Client();
        }
        return $this->httpClient;
    }


    private function createNonceStr($length = 16)
    {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }
}